/*
* 	写者优先
*/

# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>


// RWMutex 读写互斥
// mutex1 readCount互斥
// mutex2 writeCount互斥
// wrt 写者互斥
// mutex3的主要用处就是避免写者同时与多个读者进行竞争，读者中信号量RWMutex比mutex3先释放，则一旦有写者，写者可马上获得资源。
sem_t RWMutex, mutex1, mutex2, mutex3, wrt;
//用于记录正在等待的写者的数目
int writeCount, readCount;


//读者
void* Reader(void* param) {
    while (1){
        sem_wait(&mutex3);
        sem_wait(&RWMutex);
        sem_wait(&mutex2);
        readCount++;
        if(readCount == 1)
            sem_wait(&wrt);
        sem_post(&mutex2);
        sem_post(&RWMutex);
        sem_post(&mutex3);
        sleep(3);
        printf("Thread %d: is reading\n", pthread_self());
        sem_wait(&mutex2);
        readCount--;
        if(readCount == 0)
            sem_post(&wrt);
        sem_post(&mutex2);
    }
    pthread_exit(0);
}

//写者
void* Writer(void* param) {

    while (1){
        sem_wait(&mutex1);
        writeCount++;
        if(writeCount == 1){
            sem_wait(&RWMutex);
        }
        sem_post(&mutex1);
        sem_wait(&wrt);
        sleep(5);
        printf("Thread %d: is writing\n", pthread_self());
        sem_post(&wrt);
        sem_wait(&mutex1);
        writeCount--;
        if(writeCount == 0) {
            sem_post(&RWMutex);
        }
        sem_post(&mutex1);
    }
    pthread_exit(0);
}

void choiceMenu(){
    printf("选择一种情况：\n");
    printf("1.写者线程正在运行，读者线程到达\n"
           "2.读者线程运行，写者线程到达\n"
           "3.读者线程运行，另一个读者线程到达\n"
           "4.写者线程运行，另一个写者线程到达\n"
           "5.退出\n");
}

int main() {

    pthread_attr_t attr;

    pthread_attr_init(&attr);

    //initial the semaphores
    sem_init(&mutex1, 0, 1);
    sem_init(&mutex2, 0, 1);
    sem_init(&mutex3, 0, 1);
    sem_init(&wrt, 0, 1);
    sem_init(&RWMutex, 0, 1);

    readCount = writeCount = 0;
    pthread_t rid,wid;
    //模拟几种情况
    int num;
    choiceMenu();
    while(1){
        scanf("%d",&num);
        switch(num){
            //写者线程正在运行，读者线程到达
            case 1:
                pthread_create(&wid, &attr, Writer, NULL);
                //运行10秒
                sleep(10);
                pthread_create(&rid,&attr, Reader ,NULL);
                break;
                //读者线程运行，写者线程到达
            case 2:
                pthread_create(&rid, &attr, Reader, NULL);
                //运行10秒
                sleep(10);
                pthread_create(&wid,&attr, Writer ,NULL);
                break;
                //读者线程运行，另一个读者线程到达
            case 3:
                pthread_create(&rid, &attr, Reader, NULL);
                //运行10秒
                sleep(10);
                pthread_create(&rid, &attr, Reader ,NULL);
                break;
                //写者线程运行，另一个写者线程到达
            case 4:
                pthread_create(&wid, &attr, Writer, NULL);
                //运行10秒
                sleep(10);
                pthread_create(&wid, &attr, Writer ,NULL);
                break;
            case 5:
                return;
        }
    }
    sem_destroy(&mutex1);
    sem_destroy(&mutex2);
    sem_destroy(&mutex3);
    sem_destroy(&RWMutex);
    sem_destroy(&wrt);
    return 0;
}
